
/*    This file is part of the Managarm operating system.
 *   Copyright (C) 2007, 2008, 2009  Alexander van der Grinten
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

import java.io.*;
import java.util.*;

public class InitrdTool {
	private static final int RDCLS_END = 0;
	private static final int RDCLS_FILE = 1;
	
	private static void printUsage() {
		System.err.println("Usage:");
		System.err.println("java InitrdTool [arguments..]");
		System.err.println("-o <filename>    write the initrd to the file <filename>");
		System.err.println("-i <filename>    include <filename> into the initrd");
	}

	// writes an unsigned integer value to a stream
	private static void writeUInt(long value,
			OutputStream stream) throws IOException {
		stream.write((int)(value & 0xFF000000L) >> 24);
		stream.write((int)(value & 0xFF0000L) >> 16);
		stream.write((int)(value & 0xFF00L) >> 8);
		stream.write((int)(value & 0xFFL));
	}
	
	// writes an unsigned short value to a stream
	private static void writeUShort(int value,
			OutputStream stream) throws IOException {
		stream.write((value & 0xFF00) >> 8);
		stream.write(value & 0xFF);
	}
	
	// the output file is specified by -o filename
	// input files can be specified by -i filename
	public static void main(String[] args) {
		// create a new linked list to memorize our input files
		LinkedList<String> input = new LinkedList<String>();
		
		// this variable memorizes our output file name
		String output = null;
		
		// process our arguments
		for(int i = 0; i < args.length; i++) {
			if(args[i].equals("-o")) {
				output = args[i + 1];
				i++;
			}else if(args[i].equals("-i")) {
				input.add(args[i + 1]);
				i++;
			}else{
				System.err.println("Invalid invocation");
				printUsage();
				System.exit(-1);
			}
		}
		
		// check for errors
		if(output == null) {
			System.err.println("No output file specified");
			printUsage();
			System.exit(-1);
		}
		
		//System.out.println("Output file: " + output);
		
		// open the output file
		OutputStream stream = null;
		
		try {
			stream = new FileOutputStream(output);
		} catch(IOException e) {
			System.err.println("Io exception while opening the output file");
			System.exit(-1);
		}
		
		// traverse the input file list and copy the files into the image
		Iterator<String> initer = input.iterator();
		while(initer.hasNext()) {
			String infilename = initer.next();
			
			// construct a file object for the input file
			// we have to get the file length
			// and other information about the file
			File infile = new File(infilename);
			
			// get the file name and the file length
			long filesz = infile.length();
			String filename = infile.getName();
			
			// open the input file
			InputStream instream = null;
			
			try {
				instream = new FileInputStream(infile);
			} catch(FileNotFoundException e) {
				System.err.println("Could not open " + infilename);
				System.exit(-1);
			}

			// write a "file" token
			try {
				writeUInt(RDCLS_FILE, stream);
				writeUInt(filename.length(), stream);
				writeUInt(filesz, stream);
				for(int i = 0; i < filename.length(); i++)
					writeUInt((int)filename.charAt(i), stream);
			} catch(IOException e) {
				System.err.println("Could not write to the output file");
				System.exit(-1);
			}
				
			
			// copy the file contents to the initrd
			try {
				for(long i = 0; i < filesz; i++)
					stream.write(instream.read());
			} catch(IOException e) {
				System.err.println("Could not copy data from the" +
						" input file to the output file");
				System.exit(-1);
			}
			
			// close the input stream
			try {
				instream.close();
			} catch(IOException e) {
				System.err.println("Could not close the input file");
				System.exit(-1);
			}
		}
		
		// write a "end of initrd" token
		try {
			writeUInt(RDCLS_END, stream);
		} catch(IOException e) {
			System.err.println("Could not write to the output file");
			return;
		}
		
		// close the output stream
		try {
			stream.close();
		} catch(IOException e) {
			System.err.println("Could not close the output file");
			return;
		}
	}
}
